﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.IO;

namespace Mac
{
    class Mac
    {

        static byte[] key = HexStringToByteArray("404142434445464748494A4B4C4D4E4F");
       
        static private byte[] HexStringToByteArray(string hexString)
        {
            byte[] res = new byte[hexString.Length / 2];
            for (int i = 0; i < hexString.Length; i += 2)
            {
                res[i / 2] = Convert.ToByte(hexString.Substring(i, 2), 16);
            }
            return res;
        }
        static private string ByteArrayToHexString(byte[] res)
        {
            StringBuilder sb = new StringBuilder();

            for (int i = 0; i < res.Length; i++)
            {
                sb.Append(Convert.ToString(res[i], 16).ToUpper().PadLeft(2, '0'));
            }

            return sb.ToString();
        }
        public static string Encrypt(string decryptedString)
        {
            DESCryptoServiceProvider desProvider = new DESCryptoServiceProvider();
            desProvider.Mode = CipherMode.ECB;
            desProvider.Padding = PaddingMode.None;
           
            byte[] keyLeft = new byte[8];
            byte[] keyRight = new byte[8];
            for (short i = 0; i < 8; i++)
            {
                keyLeft[i] = key[i];
                keyRight[i] = key[i + 8];
            }
            desProvider.Key = keyLeft;
            using (MemoryStream stream = new MemoryStream())
            {
                using (CryptoStream cs = new CryptoStream(stream, desProvider.CreateEncryptor(), CryptoStreamMode.Write))
                {
                    byte[] data = HexStringToByteArray(decryptedString);
                    byte[] paddedData1 = generatePaddedDataByteArray(data);
                    byte[] mac = new byte[8];
                    short noOfDataBlocks = (short)(paddedData1.Length / 8);
                    short j = 0;
                    for (short i = 0; i < noOfDataBlocks; i++)
                    {
                        mac = doXOR(paddedData1, (short)j, (short)8, mac);
                        cs.Write(mac, 0, mac.Length);
                        Array.Copy(stream.ToArray( ),j,mac,0,8);
                        j = (short)(j + 8);
                    }
                     mac = Decrypt((mac), keyRight);
                     cs.Write(mac, 0, mac.Length);
                     Array.Copy(stream.ToArray(), j, mac, 0, 8);
                     return ByteArrayToHexString(mac);
                }
            }
        }
        public static byte[] Decrypt(byte[] encryptedString,byte[] keyNew)
        {
            DESCryptoServiceProvider desProvider = new DESCryptoServiceProvider();
            desProvider.Mode = CipherMode.ECB;
            desProvider.Padding = PaddingMode.None;
            desProvider.Key = keyNew;
            using (MemoryStream stream = new MemoryStream((encryptedString)))
            {
                using (CryptoStream cs = new CryptoStream(stream, desProvider.CreateDecryptor(), CryptoStreamMode.Write))
                {
                    cs.Write(encryptedString,0,8);
                    Array.Copy(stream.ToArray(), 0, encryptedString, 0, 8);
                    return encryptedString;
                }
            }
        }
        private static byte[] generatePaddedDataByteArray(byte[] buffer) {
			
		  int	originalDataByteArrayLength=buffer.Length;
			int bytesToBePadded =  (8 - (originalDataByteArrayLength % 8));
			int dataLengthAfterPad=(bytesToBePadded+originalDataByteArrayLength);
			
			byte [] paddedData=new byte[dataLengthAfterPad];
			for (int i = 0; i < dataLengthAfterPad; i++) {
				
				if (i == originalDataByteArrayLength)
				{
					//System.out.println(" inside if ");
					paddedData[i] = (byte) 0x80;
					break;
				}
				paddedData[i]=buffer[i];
			}
			return paddedData;
		}
        private static byte[] doXOR(byte[] paddedData, short offset, short length, byte[] byteArray)
        {
            short j = 0;
            for (short i = offset; i < offset + length; i++)
            {

                byteArray[j] ^= paddedData[i];
                j++;
            }

            return byteArray;
        }
 
    }
}
